<?php
require_once $_SERVER['DOCUMENT_ROOT'] . "/common/DbOperation.php";

class BaseCms
{
    public $param_value_key = "val";
    public $param_operation = "oper";
    public $request_error_code = 400;
    //值的变量名称
    public $permission_denied = 401;
    //条件操作方式
    public $error_page = 404;
    //请求参数错误
    public $error_code = 500;
    //权限错误
    public $error_msg = "error";
    //请求不存在错误
    public $fields = array();
    //数据库连接句柄
    public $db;
    //错误消息
//    private $prefix;
    private $tb_name;
    private $primary_key;
    private $tab_columns = array();
    private $fields_type = array();
    private $sql_columns = "*";


    function __construct($tb_name)
    {
        $this->db = DbOperation::getInstance();
        $this->tb_name = $this->getPrefix() . $tb_name;
        $this->tableInfo();
    }

    /**
     * 获取类别信息
     */
    private function tableInfo()
    {
        $datas = $this->db->tableFieldsInfo($this->tb_name);
        $this->tab_columns = $datas;
        $this->sql_columns = "";
        $data_type = array();
        foreach ($datas as $val) {
            if ($val["COLUMNKEY"] == "PRI") {
                $this->primary_key = $val["COLUMNNAME"];
            }
            $data_type[$val["COLUMNNAME"]] = $val["DATATYPE"];
            $this->fields[] = $val["COLUMNNAME"];
            $this->sql_columns .= $val["COLUMNNAME"] . ",";
        }
        $this->fields_type = $data_type;
        $this->sql_columns = substr($this->sql_columns, 0, strlen($this->sql_columns) - 1);
    }

    /**
     * 执行自定义sql
     * @param $sql
     * @return DbOperation|mixed
     */
    function execute($sql)
    {
        return $this->db->execute($sql);
    }

    /**
     * 获取主键
     */
    function getPrimaryKey()
    {
        if (!$this->primary_key) {
            $this->result("内部异常", $this->error_msg, $this->error_code);
            die(-1);
        }
        return $this->primary_key;
    }

    /**
     * 请求结果返回
     * @param $data 数据
     * @param string $msg 消息
     * @param int $code 编码
     * @param bool $is_login 是否登录
     */
    function result($data, $msg = "success", $code = 200, $is_login = false)
    {
        $result = ["data" => $data, "cnMessage" => $msg, "code" => $code];
        if ($is_login) {
            $result["token"] = md5(json_encode($data));
        }
        echo json_encode($result);
    }

    /**
     * 获取表前缀
     * @return mixed
     */
    function getPrefix()
    {
        return $this->db->getPrefix();
    }

    /**
     * 根据条件查询条数据
     * @param $condition 条件
     * @param array $orderBy 排序
     * @return mixed
     */
    function findOne($condition = array(), $orderBy = array())
    {
        $sql = "select $this->sql_columns from $this->tb_name ";
        $sql .= $this->assignParam($condition, $orderBy);
        return $this->db->selectOne($sql);
    }

    /**
     * 参数赋值
     * @param array $condition 条件
     * @param array $orderBy 排序
     * @return false|string
     */
    private function assignParam($condition = array(), $orderBy = array())
    {
        $sql = "";
        if (!empty($condition)) {
            $sql .= "where 1=1 ";
            foreach ($condition as $key => $val) {
                if (is_array($val)) {
                    $sql .= " and $key ";
                    $oper = $val[$this->param_operation];
                    $temp_val = $val[$this->param_value_key];
                    if ($oper == "in") {
                        $sql .= " in ($temp_val)";
                    } else if ($oper == "nin") {
                        $sql .= " not in($temp_val)";
                    } else if ($oper == "btn") {
                        $sql .= " between $temp_val[0] and $temp_val[1]";
                    } else {
                        $sql .= $oper;
                        $type = strtolower($this->fields_type[$key]);
                        if ($type == "int" || $type == "number" || $type == "double"
                            || $type == "long" || $type == "bigint") {
                            $sql .= " " . (!$temp_val ? 0 : $temp_val) . " ";
                        } else {
                            //  error_log("$temp_val--" . mysqli_real_escape_string($this->db, $temp_val));
                            $sql .= " '" . $this->post_check($temp_val) . "' ";
                        }
                    }

                } else {
                    $sql .= " and $key=";
                    $type = strtolower($this->fields_type[$key]);
                    if ($type == "int" || $type == "number" || $type == "double"
                        || $type == "long" || $type == "bigint") {
                        $sql .= (!$val ? 0 : $val);
                    } else {
                        // error_log("$val--" . mysqli_real_escape_string($this->db, $val));
                        $sql .= " '" . $this->post_check($val) . "' ";
                    }

                }

            }
        }
        if (!empty($orderBy)) {
            $sql .= " order by ";
            foreach ($orderBy as $key => $val) {
                $sql .= " $key $val,";
            }
            $sql = substr($sql, 0, strlen($sql) - 1);
        }
        return $sql;
    }

    /**
     * 防止sql注入自定义方法一
     * @param: mixed $value 参数值
     */

    function check_param($value = null)
    {
        #  select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile
        $str = 'select|insert|and|or|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile';
        if (!$value) {
            return $value;
        } elseif (preg_match($str, $value)) {
            exit('参数非法！');
        }
        return $value;
    }

    /**
     * 防止sql注入自定义方法二
     * @param: mixed $value 参数值
     */
    function str_check($value)
    {
        if (!get_magic_quotes_gpc()) {
            // 进行过滤
            $value = addslashes($value);
        }
        $value = str_replace("_", "\_", $value);
        $value = str_replace("%", "\%", $value);
        return $value;
    }

    /**
     * 防止sql注入自定义方法三
     * @param: mixed $value 参数值
     */
    function post_check($value)
    {
        if (!get_magic_quotes_gpc()) {
            // 进行过滤
            $value = addslashes($value);
        }
//        $value = str_replace("_", "\_", $value);
//        $value = str_replace("%", "\%", $value);
        $value = nl2br($value);
        $value = htmlspecialchars($value);
        return $value;

    }

    /**
     * 根据条件查询所有满足条件的数据
     * @param $tb_name 表名
     * @param array $condition 条件
     * @return array|mixed
     */
    function findList($condition = array(), $orderBy = array())
    {
        $sql = "select $this->sql_columns from $this->tb_name ";
        $sql .= $this->assignParam($condition, $orderBy);
        return $this->db->selectList($sql);
    }

    /**
     * 分页查询数据
     * @param $currentPage
     * @param $pageSize
     * @param array $condition
     * @param array $orderBy
     * @return array|mixed
     */
    function findByPage($currentPage, $pageSize, $condition = array(), $orderBy = array())
    {
        $currentPage = empty($currentPage) ? 1 : $currentPage;
        $pageSize = empty($pageSize) ? 20 : $pageSize;
        $base_sql = " from $this->tb_name ";
        $base_sql .= $this->assignParam($condition, $orderBy);
        $sql = "select $this->sql_columns $base_sql";
        $datas = $this->db->pageList($sql, $currentPage, $pageSize);
        $totals = $this->db->count($base_sql);
        $totals = (int)$totals;
        $totalPage = (int)($totals % $pageSize) == 0 ? (int)($totals / $pageSize) : (int)($totals / $pageSize) + 1;
        $redata = array();
        $redata["dataList"] = $datas;
        $redata["totalPages"] = $totalPage;
        $redata["currentPage"] = $currentPage;
        $redata["totalDatas"] = $totals;
        return $redata;
    }

    /**
     * 统计数据条数
     * @param array $condition 条件
     * @return mixed
     */
    function count($condition = array())
    {
        $sql = "select count(1) as total from $this->tb_name ";
        $sql .= $this->assignParam($condition);
        $data = $this->db->selectOne($sql);
        return $data->total;
    }

    /**
     * 编辑数据
     * @param $tb_name 表名
     * @param $parameter_key 主键名
     * @param $data 数据
     * @throws ErrorException
     */
    function merge($parameter_key, $data)
    {
        assert(!empty($data), "数据不能为空");
        $data_id = $data["data_no"];
        $is_insert = false;
        if (isset($data[$parameter_key])) {
            $sql = "select $this->sql_columns from $this->tb_name where $parameter_key=$data[$parameter_key]";
            $redata = $this->db->selectOne($sql);
            if (!empty($redata)) {
                $sql = "update $this->tb_name set ";
                foreach ($data as $key => $val) {
                    $sql .= "$key='" . $val . "',";
                }
                $sql = substr($sql, 0, strlen($sql) - 1);
                $sql .= " where $parameter_key=$data[$parameter_key]";
            }
        } else {
            $sql = "insert into $this->tb_name";
            $filed = "";
            $values = "";
            foreach ($data as $key => $val) {
                $filed .= $key . ",";
                $values .= "'" . $val . "',";
            }
            $data_id = $this->assignProps($filed, $values);
            $filed = substr($filed, 0, strlen($filed) - 1);
            $values = substr($values, 0, strlen($values) - 1);
            $sql .= "($filed)values($values)";
            $is_insert = true;
        }
        if (!$this->db->execute($sql)) {
            $msg = "表:[$this->tb_name] 执行 [$sql]异常";
            throw new ErrorException($msg);
        }
        return $data_id;
    }

    /**
     * 当前日期
     * @return string
     */
    function currentDate()
    {
        $now = new DateTime();
        return $now->format('Y-m-d');
    }

    /**
     * 当前时间
     * @return string
     */
    function currentDateTime()
    {
        $now = new DateTime();
        return $now->format('Y-m-d H:i:s');
    }

    /**
     * 赋值公共属性
     */
    function assignProps(&$filed, &$values)
    {
//        sesssion_start();
        $userName = isset($_SESSION["userInfo"]) ? $_SESSION["userInfo"]["userName"] : "NoLogin";
        $data_no = time();
        $datas = ["created_date" => $this->currentDateTime(), "updated_date" => $this->currentDateTime(), "created_by" => $userName, "updated_by" => $userName,
            "is_del" => 0, "version" => 1, "status_code" => 1, "status_name" => "正常", "local" => "zh_CN", "data_no" => $data_no];
        $temp = explode(",", $filed);
        foreach ($datas as $key => $val) {
            if (in_array($key, $this->fields) && !in_array($key, $temp)) {
                $filed .= $key . ",";
                $values .= "'" . $val . "',";
            }
        }
        return $data_no;
    }

    /**
     * 根据条件删除数据
     * @param $condition 删除数据条件
     * @return bool|mysqli_result
     */
    function delete($condition)
    {
        $sql = "delete from $this->tb_name ";
        $sql .= $this->assignParam($condition);
        return $this->db->execute($sql);
    }


    /**
     * 查询条件组装
     * @param int $request_type
     * @return array
     */
    function searchData($request_type = 0)
    {
        $data = array();
        foreach ($this->fields as $key => $val) {
            $pVal = $this->toCamelCase($val);
            $temp = "";
            if ($request_type == 1) {
                if (isset($_GET[$pVal])) {
                    $temp = $_GET[$pVal];
                }
            } else if ($request_type == 2) {
                if (isset($_REQUEST[$pVal])) {
                    $temp = $_REQUEST[$pVal];
                }
            } else {
                if (isset($_POST[$pVal])) {
                    $temp = $_POST[$pVal];
                }
            }
//            error_log(json_encode($this->fields_type));
            $type = strtolower($this->fields_type[$val]);
//            error_log($val."------------".$temp."type:".$type);
            if (!empty($temp) || $temp == "0") {
                if ($type == "int" || $type == "number" || $type == "double"
                    || $type == "long" || $type == "bigint") {
                    $data[$val] = [$this->param_operation => "=", $this->param_value_key => $temp];
                } else if ($type == "datetime" || $type == "timestamp") {
                    $t_data = explode(",", $temp);
                    $data[$val] = sizeof($data) == 2 ? [$this->param_operation => "btn", $this->param_value_key => $t_data]
                        : [$this->param_operation => "<=", $this->param_value_key => $temp];
                } else if ($type == "varchar" || $type == "text" || $type == "longtext") {
                    $data[$val] = [$this->param_operation => "like", $this->param_value_key => "%$temp%"];
                } else {
                    $data[$val] = [$this->param_operation => "=", $this->param_value_key => $temp];
                }
            }
        }
//        error_log(json_encode($data));
        return $data;
    }

    /**下划线命名到驼峰命名
     * @param $str
     * @return mixed|string
     */
    function toCamelCase($str)
    {
        $array = explode('_', $str);
        $result = $array[0];
        $len = count($array);
        if ($len > 1) {
            for ($i = 1; $i < $len; $i++) {
                $result .= ucfirst($array[$i]);
            }
        }
        return $result;
    }

    /**
     * 解析请求数据
     * @param int $request_type 1 Get 请求 0 Post请求 默认0
     * @return array
     */
    function parseRequestData($request_type = 0)
    {
        $data = array();
//        print_r($_POST);
        foreach ($this->fields as $key => $val) {
            $pVal = $this->toCamelCase($val);
//            error_log($pVal . "--" . $request_type . "---post:" . isset($_POST[$pVal]) . "---get:" . isset($_GET[$pVal]) . "---request:" . isset($_REQUEST[$pVal]));
//            error_log($pVal . "--" . $request_type . "---post:" . $_POST[$pVal] . "---get:" . $_GET[$pVal] . "---request:" . $_REQUEST[$pVal]);
            if ($request_type == 1) {
                if (isset($_GET[$pVal])) {
                    $data[$val] = $_GET[$pVal];
                }
            } else if ($request_type == 2) {
                if (isset($_REQUEST[$pVal])) {
                    $data[$val] = $_REQUEST[$pVal];
                }
            } else {
                if (isset($_POST[$pVal])) {
                    $data[$val] = $_POST[$pVal];
                }
            }
            //如果是修改数据,则修改更新日期为当前日期
            if (!empty($data) && $pVal == "updatedDate") {
                $data[$val] = $this->currentDateTime();
            }
            $type = strtolower($this->fields_type[$val]);
            if (empty($data[$val]) && $val != $this->getPrimaryKey() && ($type == "int" || $type == "number" || $type == "long")) {
                $data[$val] = 0;
            }
        }
        error_log($data);
        return $data;
    }

    /**驼峰命名转下划线命名
     * @param $str
     * @return string
     */
    function toUnderScore($str)
    {
        $dstr = preg_replace_callback('/([A-Z]+)/', function ($matchs) {
            return '_' . strtolower($matchs[0]);
        }, $str);
        return trim(preg_replace('/_{2,}/', '_', $dstr), '_');
    }

    /**
     * 检查是否登录
     */
    public function loginCheck()
    {
        session_start();
        $token = $_REQUEST["token"];
        $users = $_SESSION["userInfo"];
        $users["password"] = null;
        $uid = md5(json_encode($users));
        if ($token !== $uid) {
            $code = 401;
            $message = "非法访问,请登录后再操作";
            $this->result("", $message, $code);
            die(-1);
        }
    }
}